﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using ESRI.ArcGIS.DataSourcesFile;
using ESRI.ArcGIS.DataSourcesGDB;
using ESRI.ArcGIS.Geodatabase;
using Lwllm.ArcengineProxy.Common;
using Lwllm.ArcengineProxy.Common.Exceptions;
using Lwllm.ArcengineProxy.Core.Enums;
using Lwllm.ArcengineProxy.Core.Proxys;

namespace Lwllm.ArcengineProxy.Core
{
    /// <summary>
    /// 矢量图工作空间代理实现类
    /// </summary>
    public class FeatureWorkspaceProxy : IDisposable
    {
        private readonly string _connectionString;
        private IFeatureWorkspace _workspace;
        private List<string> _featureClassNamesCache;
        private readonly bool _withFeatureClassNamesCache;

        /// <summary>
        /// 矢量图工作空间
        /// </summary>
        /// <param name="connectionString">连接字符串</param>
        /// <param name="withFeatureClassNamesCache"></param>
        public FeatureWorkspaceProxy(string connectionString, bool withFeatureClassNamesCache = true)
        {
            _connectionString = connectionString;
            _withFeatureClassNamesCache = withFeatureClassNamesCache;
            var settings = connectionString.Split(';');
            var dbTypeSetting = settings.FirstOrDefault(str =>
                str.StartsWith("DbType=", true, CultureInfo.CurrentCulture));
            if (string.IsNullOrWhiteSpace(dbTypeSetting)
                || dbTypeSetting.Split('=').Length != 2)
                throw new WrongConnectionStringException();
            var dbTypeString = dbTypeSetting.Split('=')[1];
            var dbType = (DbTypeEnum) Enum.Parse(typeof(DbTypeEnum), dbTypeString, true);
            CreateWorkspace(settings, dbType);
        }

        public bool WorkspaceExists => _workspace != null;

        public void Dispose()
        {
            _workspace?.ComDispose();
        }

        private string GetValueString(string[] settings, string name)
        {
            var setting = settings.FirstOrDefault(s => s.StartsWith($"{name}=", true, CultureInfo.CurrentCulture));
            if (string.IsNullOrWhiteSpace(setting)
                || setting.Split('=').Length != 2)
                throw new WrongConnectionStringException();

            return setting.Split('=')[1];
        }

        private void CreateWorkspace(string[] settings, DbTypeEnum dbType)
        {
            switch (dbType)
            {
                case DbTypeEnum.ShapeFile:
                {
                    var path = GetValueString(settings, "Path");
                    if (string.IsNullOrWhiteSpace(path) || !Directory.Exists(path))
                        throw new WrongConnectionStringException();

                    CreateShapeFileWorkspace(path);
                    break;
                }

                case DbTypeEnum.Mdb:
                {
                    var path = GetValueString(settings, "Path");
                    if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
                        throw new WrongConnectionStringException();
                    CreateMdbWorkspace(path);
                    break;
                }
            }

            if (_withFeatureClassNamesCache)
            {
                _featureClassNamesCache = new List<string>();
                CacheDatasetNames();
            }
        }

        private void CacheDatasetNames()
        {
            var dsList = ((IWorkspace) _workspace).DatasetNames[esriDatasetType.esriDTAny];
            IDatasetName datasetName;
            while ((datasetName = dsList.Next()) != null)
            {
                if (datasetName is IFeatureClassName)
                {
                    _featureClassNamesCache.Add(datasetName.Name);
                }
                else if (datasetName is IFeatureDatasetName)
                {
                    var subDsList = datasetName.SubsetNames;
                    IDatasetName subDatasetName;
                    while ((subDatasetName = subDsList.Next()) != null)
                    {
                        _featureClassNamesCache.Add(subDatasetName.Name);
                    }
                }
            }
        }

        private void CreateShapeFileWorkspace(string path)
        {
            var factory = new ShapefileWorkspaceFactory();
            _workspace = (IFeatureWorkspace) factory.OpenFromFile(path, 0);
        }

        private void CreateMdbWorkspace(string path)
        {
            var factory = new AccessWorkspaceFactory();
            _workspace = (IFeatureWorkspace) factory.OpenFromFile(path, 0);
        }

        /// <summary>
        /// 获取图层
        /// </summary>
        /// <param name="featureClassName">图层名称</param>
        /// <param name="featureProxy"></param>
        /// <returns>返回对应的featureclass代理</returns>
        public FeatureClassProxy GetFeatureClass(string featureClassName)
        {
            if (_withFeatureClassNamesCache && !_featureClassNamesCache.Contains(featureClassName))
            {
                return null;
            }

            try
            {
                var featureClass = _workspace.OpenFeatureClass(featureClassName);
                return new FeatureClassProxy(featureClass);
            }
            catch
            {
                //ignore
            }

            return null;
        }
    }
}